<template>
  <a-modal v-model:visible="visible" unmountOnClose v-bind="config" ref="dialogRef" @close="onResetData">
    <template #title>
      <div style="position: absolute; left: 15px;">
        <component :is="config.titleIcon || ''" style="font-size: 18;" />
        {{ config.title }}
      </div>
    </template>
    <div>
      <slot name="dialog-content">
        <a-form :model="formData" layout="horizontal" v-bind="config.formConfig" auto-label-width ref="submitRef">
          <a-row :gutter="0">
            <a-col :span="(24 / config.formConfig.itemLine)" v-for="(item, idx) in config.formConfig.formItem" :key="idx">
              <a-form-item :field="item.field" :label="item.label" :rules="item.rule" v-if="item.type !== 'hide'">
                <a-input v-if="item.type === 'input'" v-model="formData[item.field]" :placeholder="'请输入'+item.label" v-bind="item" :default-value="item.defaultVal" />
                <a-select v-else-if="item.type === 'select'" v-model="formData[item.field]" v-bind="item" :loading="selectLoading" :options="item.options.length > 0 ? item.options : selectOptions[item.field]" :placeholder="'请选择'+item.label" allow-search />
                <a-switch v-else-if="item.type === 'switch'" v-model="formData[item.field]" v-bind="item" :checked-value="1" :unchecked-value="0" :default-checked="item.defaultVal">
                  <template #checked-icon>
                    <icon-check />
                  </template>
                  <template #unchecked-icon>
                    <icon-close />
                  </template>
                </a-switch>
                <a-space direction="vertical" size="large" v-else-if="item.type === 'radio'">
                  <a-radio-group v-model="formData[item.field]" v-bind="item" :default-value="item.defaultVal">
                    <a-radio :value="option.value" v-for="(option, index) in item.options" :key="index+idx">{{ option.label }}</a-radio>
                  </a-radio-group>
                </a-space>
                <a-cascader v-else-if="item.type === 'cascader'" :options="cascaderOptions" v-model="formData[item.field]" :placeholder="'请选择'+item.label" :loading="selectLoading" v-bind="item" check-strictly allow-clear />
                <a-tree-select v-else-if="item.type === 'treeselect'" :data="treeSelectOptions" v-model="formData[item.field]" @popup-visible-change="treeSelectChangeHandler(formData['id'])" :placeholder="'请选择'+item.label" :loading="selectLoading" v-bind="item" check-strictly allow-clear />
                <a-tree v-else-if="item.type === 'tree'" ref="treeRef" :checked-keys="formData[item.field]" @check="keys => formData[item.field] = keys" blockNode checkable multiple :loading="selectLoading" style="width: 100%; height: 25vh;" :data="treeOptions" v-bind="item">
                  <template #extra="nodeData">
                    <div style="position: absolute; right: 8px; font-size: 12px; top: 10px; color: #3370ff;">
                      <a-space>
                        <a-tooltip content="基础菜单(不可操作)" position="left">
                          <TournamentIcon v-if="nodeData.basics" style="width: 18px; height: 18px;" />
                        </a-tooltip>
                      </a-space>
                    </div>
                  </template>
                </a-tree>
                <a-popover title="图标" trigger="click" v-else-if="item.type === 'icon-select'" position="rt">
                  <a-input readonly v-bind="item" v-model="formData[item.field]" :placeholder="'请选择'+item.label">
                    <template #prefix>
                      <component :is="formData[item.field]" style="font-size: 25px;" />
                    </template>
                  </a-input>
                  <template #content>
                    <div style="width: 25vw; overflow: hidden;">
                      <a-list @reach-bottom="loadMoreIcons" :max-height="500" :split="false" :loading="iconsLoading">
                        <a-list-item>
                          <Icons :icons="icons" :field="item.field" @updateForm="selectIconHandler" />
                        </a-list-item>
                      </a-list>
                    </div>
                  </template>
                </a-popover>
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
      </slot>
    </div>
    <template #footer>
      <a-button type="primary" size="small" status="danger" @click="hide">取消</a-button>
      <a-button type="primary" size="small" @click="handleSubmit" :loading="submitBtnLoading">提交</a-button>
    </template>
  </a-modal>
</template>

<script lang="ts">
import {
  defineComponent,
  ref,
  nextTick,
  onMounted,
  h,
  reactive,
  toRaw,
} from "vue";
import { uniRequest } from "@/api/uni-apis";
import ArcoVueIcon from "@arco-design/web-vue/es/icon";
import * as VTIsonc from "vue-tabler-icons";
import Icons from "./common/Icons.vue";

export default defineComponent({
  components: { Icons },
  props: {
    config: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  emits: ["onRefresh"],
  setup(props, ctx) {
    const visible = ref(false);
    const formData = ref({});
    const action = ref("");
    const submitRef = ref(null);
    const dialogRef = ref(null);
    const submitBtnLoading = ref(false);
    const selectLoading = ref(false);
    const iconsLoading = ref(false);
    const selectOptions = ref([]);
    const cascaderOptions = ref([]);
    const treeSelectOptions = ref([]);
    const treeOptions = ref([]);
    const checkedKeys = ref([]);
    const AllIcons = ref({});
    const icons = ref({});
    const treeRef = ref();
    const iconsPage = reactive({
      page: 0,
      size: 150,
    });

    AllIcons.value = Object.assign({}, ArcoVueIcon, VTIsonc);

    //提交表单
    const handleSubmit = () => {
      submitBtnLoading.value = true;
      submitRef.value.validate(async (errs) => {
        try {
          if (!errs) {
            updateDefaultValueToFormData();
            cleanEccedenzaParams();
            const data = treeHalfSelectedNodes(toRaw(formData.value));
            await uniRequest(action.value.api, action.value.method, data);
            ctx.emit("onRefresh");
            hide();
          }
        } catch (e) {
          console.error("请求异常: ", e);
        } finally {
          submitBtnLoading.value = false;
        }
      });
    };
    //获取树型结构的半选状态节点的ID //不需要请屏蔽 handleSubmit相关调用
    const treeHalfSelectedNodes = (forms) => {
      if (treeRef.value) {
        const form = props.config.formConfig.formItem.find(
          (item) => item["type"] === "tree"
        );
        treeRef.value[0]
          .getHalfCheckedNodes()
          .map((node) => node.key)
          ?.forEach((id) => {
            const exsit = forms[form.field].some((key) => key === id);
            if (!exsit) forms[form.field].push(id);
          });
      }
      return forms;
    };

    //提交数据时处理存在默认值的表单项
    const updateDefaultValueToFormData = () => {
      props.config.formConfig.formItem.forEach((item) => {
        if (item.defaultVal != undefined) {
          if (formData.value[item.field] === undefined) {
            formData.value[item.field] = item.defaultVal;
          }
        }
      });
    };
    //清理掉多余字段
    const cleanEccedenzaParams = () => {
      const data = formData.value;
      const formItems = props.config.formConfig.formItem;
      Object.keys(data).forEach((key) => {
        if (!formItems.some((item) => item["field"] === key || key === "id")) {
          delete formData.value[key];
        }
      });
    };
    //显示dialog
    const show = function (title: any, api: string, data = undefined) {
      nextTick(() => {
        action.value = api;
        formData.value = Object.assign(
          {},
          data,
          props.config.formConfig.extraFormData
        );
        const formItem = props.config.formConfig.formItem.find((item) =>
          ["tree"].includes(item["type"])
        );
        if (formItem) {
          const field = formItem.field;
          if (!formData.value[field]) formData.value[field] = [];
          checkedKeys.value.forEach((key) => {
            const isExsit = formData.value[field]?.some((k) => k === key);
            if (!isExsit) {
              formData.value[field].push(key);
            }
          });
        }
        props.config.title = title;
        visible.value = true;
      });
    };

    //关闭dialog
    const hide = () => {
      onResetData();
      visible.value = false;
    };
    //重置表单以及数据
    const onResetData = () => {
      submitRef.value.resetFields();
      submitRef.value = undefined;
    };

    //图标选择器
    const selectIconHandler = (field, icon) => {
      formData.value[field] = icon;
    };

    const loadCascaderMoreOptions = (item, type) =>
      loadMore(cascaderOptions, item.api, type, item.field);
    const loadTreeSelectMoreOptions = (item, type) =>
      loadMore(treeSelectOptions, item.api, type, item.field);
    const loadTreeMoreOptions = (item, type) =>
      loadMore(treeOptions, item.api, type, item.field);
    const loadSelectOptions = (item, type) =>
      loadMore(selectOptions, item.api, type, item.field);

    ///加载动态数据
    const isRequestApis = [];
    const loadMore = async (arr, api, type, field) => {
      if (isRequestApis.indexOf(api) > -1) return;
      isRequestApis.push(api);
      try {
        selectLoading.value = true;
        if (!arr.value.length) {
          const options = await uniRequest(api, "get", {});
          if (type === "select") {
            arr.value[field] = options?.data ?? [];
          } else if (
            type === "tree" ||
            type === "treeselect" ||
            type === "cascader"
          ) {
            const nodes = treeDataProcessor(options, field);
            arr.value = nodes;
          }
          const idx = isRequestApis.findIndex((str) => str === api);
          isRequestApis.splice(idx, 1);
        }
      } catch (e) {
        console.error("获取选项列表时发生错误: ", e);
      } finally {
        selectLoading.value = false;
      }
    };
    //组装树形数据
    const treeDataProcessor = (arr, field, pid = 0) => {
      const leay = [];
      arr.forEach((item) => {
        if (item["is_basics"] && item["is_disable"] !== 1) {
          checkedKeys.value.push(item.id);
        }
        const node = {
          title: item.name,
          pid,
          key: item.id,
          disableCheckbox: item.is_basics == 1,
          basics: item.is_basics,
          disabled: item.is_disable || item.is_basics,
          field: field,
          icon: () => h(ArcoVueIcon[item.icon]),
        };
        if (item.children && item.children.length > 0) {
          node.children = treeDataProcessor(item.children, field, item.id);
        }
        leay.push(node);
      });
      return leay;
    };
    ///初始化数据
    onMounted(() => {
      const items = props.config.formConfig.formItem;
      items
        .filter((item) => item["api"])
        .forEach((item) => {
          const type = item.type;
          if (type === "tree") {
            loadTreeMoreOptions(item, type);
          } else if (type === "treeselect") {
            loadTreeSelectMoreOptions(item, type);
          } else if (type === "cascader") {
            loadCascaderMoreOptions(item, type);
          } else if (type === "select") {
            loadSelectOptions(item, type);
          }
        });
    });
    //选项控制处理
    const treeSelectChangeHandler = (val) =>
      disabilitaRicorsiva(treeSelectOptions.value, val);
    //递归更新树形数据状态
    const disabilitaRicorsiva = (arr, val) => {
      arr.forEach((item) => {
        item["disabled"] = item["key"] === val ? true : false;
        if (item["children"] && item["children"].length > 0) {
          disabilitaRicorsiva(item["children"], val);
        }
      });
    };

    ///加载更多Icons 由于2000多个icon一次性加载过慢卡顿.
    const loadMoreIcons = () => {
      iconsLoading.value = true;
      try {
        const keys = Object.keys(AllIcons.value);
        const length = Object.keys(AllIcons.value).length;
        const index = iconsPage.page * iconsPage.size;
        if (index >= length) return;

        for (let i = 0; i < iconsPage.size; i++) {
          if (!keys[i + index]) return;
          icons.value[keys[i + index]] = AllIcons.value[keys[i + index]];
        }

        iconsPage.page++;
      } catch (e) {
      } finally {
        iconsLoading.value = false;
      }
    };

    return {
      visible,
      formData,
      submitRef,
      dialogRef,
      submitBtnLoading,
      cascaderOptions,
      treeSelectOptions,
      treeOptions,
      selectOptions,
      selectLoading,
      iconsLoading,
      icons,
      treeRef,
      handleSubmit,
      show,
      hide,
      onResetData,
      treeSelectChangeHandler,
      loadCascaderMoreOptions,
      loadTreeSelectMoreOptions,
      loadTreeMoreOptions,
      selectIconHandler,
      loadMoreIcons,
    };
  },
});
</script>

<style scoped lang="less">
</style>
